#include "opcodes.h"
#include "macros.h"
#include "functions.h"
#include "CPU_SendPort.h"
#include "CPU_CheckPort.h"
#include "CPU_Cmp.h"
#include "CPU_Alt.h"
#include "CPU_Ready.h"
#include "SYS_Timer.h"
#include "SYS_GetAgentId.h"
#include "CPU_Proc.h"
#include <stdio.h>
_OPCFun tavm_run_opcode[] =
{
    &OPCF_Nop,
    &OPCF_Start,
    &OPCF_Exit,
    &OPCF_Jump,
    &OPCF_Crit,
    &OPCF_Exec,
    &OPCF_In,
    &OPCF_Out,
    &OPCF_InProc,
    &OPCF_OutProc,
    &OPCF_Ret,
    &OPCF_Delay,
    &OPCF_Select
};
void OPCF_Nop(struct Agent_Var* agent)
{
    int r = 0;
    r += 1;
    r += 1;
}
void OPCF_Start(struct Agent_Var* agent)
{
    aid_t aid = READ_CODE(agent,aid_t);
    if(tavm_agents_v[aid].state == AS_INIT)
    {
        tavm_agents_v[aid].state = AS_READY;
    }
    else if(tavm_agents_v[aid].state == AS_FINISHED)
    {
        tavm_agents_v[aid].pc = tavm_agents_s[aid].start;
        tavm_agents_v[aid].state = AS_READY;
    }
}
void OPCF_Exit(struct Agent_Var* agent)
{
    agent->state = AS_FINISHED;
}

void OPCF_Jump(struct Agent_Var* agent)
{
    pos_t jump_pos = CPU_Alt(agent);

    agent->pc += jump_pos;

}
void OPCF_Crit(struct Agent_Var* agent)
{
    agent->critical = !(agent->critical);
}

void OPCF_Exec(struct Agent_Var* agent)
{
    fun_t fun_type = READ_CODE(agent,fun_t);

    tavm_run_exec[fun_type](agent);
}

void OPCF_In(struct Agent_Var* agent)
{
    CPU_SendPort(agent,PDIR_IN);
}

void OPCF_Out(struct Agent_Var* agent)
{
    CPU_SendPort(agent,PDIR_OUT);
}

void OPCF_InProc(struct Agent_Var* agent)
{
    CPU_Proc(agent,PDIR_IN);
}

void OPCF_OutProc(struct Agent_Var* agent)
{
    CPU_Proc(agent,PDIR_OUT);
}

void OPCF_Ret(struct Agent_Var* agent)
{
    agent->state = AS_WAITING;

    agent->pc = 0;
    tavm_agents_v[agent->procAgent].procAgent = 0;

    agent->procAgent = 0;
}

void OPCF_Delay(struct Agent_Var* agent)
{
    agent->countdown = READ_CODE(agent,time_stamp_t);
    agent->last = agent->countdown + SYS_GetCurrentTimeMs();
}

void OPCF_Select(struct Agent_Var* agent)
{
    pos_t sel_start = agent->pc - sizeof(opcode_t);
    t1B alt_count = READ_CODE(agent,t1B);

    t1B i;
    pos_t jpos = 0;

    for(i=0;i<alt_count;i++)
    {
        jpos = CPU_Alt(agent);
        if(jpos > 0)
        {
            agent->pc = sel_start + jpos;
            break;
        }
    }

    if(jpos == 0) agent->pc = sel_start;
}
